#include <wchar.h>
#include <stdint.h>
#include <stdlib.h>

#ifndef _BUF_SIZE
    #define _BUF_SIZE 1024
#elif _BUF_SIZE < 8     // 缓冲区太小会导致 wcscpy 段错误
    #error "The buffer is too small!"
#endif

#ifdef __unix__
    #define swprintf_s swprintf
    #define wcscpy_s(dest, size, src) wcscpy(dest, src)
    #define wmemmove_s(dest, size, src, count) wmemmove(dest, src, count)
#endif

void formatFileSize(uint64_t size, wchar_t **formattedSize)
{
    wchar_t buf[_BUF_SIZE];
    static const wchar_t *units[] = { L"bytes", L"KB", L"MB", L"GB", L"TB", L"PB", L"EB" };     // 64位无符号整数最大只能装到EB

    if(size > 0)
    {
        double Pow = 1;
        int digitGroups = 0;
        // 决定计数单位
        for(uint64_t i = size/1024; i > 0 && digitGroups < sizeof(units)/sizeof(units[0])-1; i /= 1024)
        {
            Pow *= 1024;
            digitGroups++;
        }

        // 因 _BUF_SIZE 可用宏修改，故加此判断处理缓冲区太小导致的失败
        if(swprintf_s(buf, _BUF_SIZE, L"%.2lf %ls", size/Pow, units[digitGroups]) <= 0)
        {
            *formattedSize = NULL;
            return;
        }

        // 消除多余的零和小数点
        wchar_t *lastDot = wcsrchr(buf, '.');
        if(lastDot)
        {
            if(lastDot[2] == '0')
            {
                size_t offset = 2;
                size_t len = wcslen(lastDot);
                if(lastDot[1] == '0')
                    offset = 0;
                for(size_t i = offset; i < len+offset-2; i++) lastDot[i] = lastDot[i-offset+3];
            }
        }
    }
    // 处理文件大小为0字节的情况
    else wcscpy_s(buf, _BUF_SIZE, L"0 bytes");

    // 分配内存创建宽字符串
    size_t len = wcslen(buf) + 1;
    *formattedSize = (wchar_t*)malloc(len * sizeof(wchar_t));
    if(*formattedSize != NULL)
        wmemmove_s(*formattedSize, len, buf, len);

    return;
}

int main(int argc, const char **argv)
{
    wchar_t *zSize;
    if(argc != 2)
        return -1;

    formatFileSize(atoll(argv[1]), &zSize);
    wprintf(L"%ls\n", zSize);
    if(zSize) free(zSize);

    return 0;
}
